/*
 * G2OSummary.cpp
 *
 *  Created on: Sep 11, 2016
 *      Author: ubuntu
 */

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../common.h"
#include "../Conf.h"
#include "G2OParse.h"

#include "G2OSummary.h"

using namespace std;

G2OSummary::G2OSummary() : Summary()
{
	m_pbuf = NULL;
	m_len = 0;
	memset(&msg, 0, sizeof(msg));
	memset(m_obdid, 0, sizeof(m_obdid));
}

G2OSummary::~G2OSummary()
{
	if (m_pbuf)
		free(m_pbuf);
	G2O_free_msg(&msg);
}

void G2OSummary::getBuf(unsigned char *buf, size_t len)
{
	m_pbuf = buf;
	m_len = len;
}

void G2OSummary::parse()
{
	int min_len = DM_TAG_HEAD_LEN + 5;
	if (!m_pbuf || m_len <= min_len) {
		debug(LOG_DEBUG, "天大的笑话");
		return;
	}
	unsigned char *p = m_pbuf + min_len;
	size_t nLen = m_len - min_len;

	int pos = DM_TAG_HEAD_LEN + 1;

	msg.curtime = m_pbuf[pos] << 24 | m_pbuf[pos+1] << 16 | m_pbuf[pos+2] << 8 | m_pbuf[pos+3];
	pos += 4;
	memcpy(m_obdid, m_pbuf+pos, 12);
	pos += 12;

	parseBuf(m_pbuf+pos, m_len - pos);

	free(m_pbuf);
	m_pbuf = NULL;
}

void G2OSummary::parseBuf(unsigned char *buf, size_t len)
{
	G2OParsePackage(buf, len, &msg);
}

void G2OSummary::debugInfo()
{
	switch (msg.id) {
	case G2O_LOGIN:
		{
			if (msg.login) {
				struct g2o_login *login = msg.login;
				debug(LOG_DEBUG, "登录请求:\n"
				"开发代码: %s, 设备ID: %s\n"
				"设备密钥: %s\n"
				"IMEI: %s, SIM: %s\n"
				"设备版本: %s", 
				login->dp_code, login->obdid,
				login->dev_key, login->dev_imei, login->dev_sim,
				login->dev_version
				);
			} else {
				debug(LOG_DEBUG, "解析不到位");
			}
		}
		break;
	case G2O_CONFIG_INFO:
		{
			debug(LOG_DEBUG, "配置信息");
		}
		break;
	case G2O_WARN_MSG:
		{
			if (!msg.warn) {
				debug(LOG_DEBUG, "报警消息有点儿邪乎啊");
				break;
			}
			struct g2o_warn *warn = msg.warn;
			switch (warn->id) {
			case G2O_WARN_TYPE_TIRED:
				debug(LOG_DEBUG, "连接驾驶报警: %s", warn->warn_msg ? warn->warn_msg : "无效数据"); 
				break;
			case G2O_WARN_TYPE_IDLE:
				debug(LOG_DEBUG, "怠速报警: %s", warn->warn_msg ? warn->warn_msg : "无效数据"); 
				break;
			case G2O_WARN_TYPE_FAST:
				debug(LOG_DEBUG, "急加速报警: %s", dateftime(msg.ts, "%F %H:%M:%S").c_str()); 
				break;
			case G2O_WARN_TYPE_DESC:
				debug(LOG_DEBUG, "急减速报警: %s", dateftime(msg.ts, "%F %H:%M:%S").c_str());
				break;
			case G2O_WARN_TYPE_VIBRATION:
				debug(LOG_DEBUG, "驻车震动报警: %s", dateftime(msg.ts, "%F %H:%M:%S").c_str());
				break;
			case G2O_WARN_TYPE_STARTUP:
				debug(LOG_DEBUG, "车辆启动报警: %s", warn->warn_msg ? warn->warn_msg : "无效数据"); 
				break;
			case G2O_WARN_TYPE_SHARP_TURN:
				debug(LOG_DEBUG, "急转弯报警: %s", warn->warn_msg ? warn->warn_msg : "无效数据"); 
				break;
			case G2O_WARN_TYPE_INSERT_PULLED:
				debug(LOG_DEBUG, "插入拔出报警: %s", dateftime(msg.ts, "%F %H:%M:%S").c_str()); 
				break;
			default:
				debug(LOG_DEBUG, "未知报警类型: %04X : %s", warn->id, warn->warn_msg ? warn->warn_msg : "无效数据"); 
				break;
			}
		}
		break;
	case G2O_TRAVEL_STCS:
		{
			if (msg.travel == NULL) {
				debug(LOG_DEBUG, "不正常的行程统计");
				break;
			}
			struct g2o_travel *travel = msg.travel;
			switch (travel->type) {
				case G2O_TRAVEL_TYPE_START:
					debug(LOG_DEBUG, "行程开始: %d, %s", travel->number, dateftime(travel->ts, "%F %H:%M:%S").c_str());
					break;
				case G2O_TRAVEL_TYPE_FINISH:
					debug(LOG_DEBUG, "行程结束: %d, %s\n"
					"开始GPS: %lf, %lf; 结束GPS: %lf, %lf\n"
					"怠数次数: %d, 怠速时间: %d, 里程: %.2f, 油耗: %.2f"
					, travel->number, dateftime(travel->ts, "%F %H:%M:%S").c_str(),
					travel->lng_start, travel->lat_start, travel->lng_end, travel->lat_end, 
					travel->idling_cnt, travel->idling_tm, travel->mileage * 0.01, travel->oil * 0.01);
					break;
				case G2O_TRAVEL_TYPE_GPS_START:
					debug(LOG_DEBUG, "GPS行程开始: %d, %s", travel->number, dateftime(travel->ts, "%F %H:%M:%S").c_str());
					break;
				case G2O_TRAVEL_TYPE_GPS_FINISH:
					debug(LOG_DEBUG, "GPS行程结束: %d, %s", travel->number, dateftime(travel->ts, "%F %H:%M:%S").c_str());
					break;
				default:
					debug(LOG_DEBUG, "未知行程统计消息类型");
					break;
			}
		}
		break;
	case G2O_PACKED_DATA:
		{
			struct g2o_gps *gps = msg.gps;
			for (; gps; gps = gps->next) {
				debug(LOG_DEBUG, "GPS数据: \n"
				"时间: %s\n"
				"定位模式: %d, 方向: %d, 速度: %d, 高度: %d\n"
				"经度: %lf, 纬度: %lf",
				dateftime(gps->ts, "%F %H:%M:%S").c_str(),
				gps->position_mode, gps->direction,
				gps->speed, gps->height,
				gps->longitude, gps->latitude
				);
			}
			struct g2o_data_stream *stream = msg.stream;
			for (; stream; stream = stream->next) {
				int i = 0;
				char tmp[1024];
				int n = 0;
				while (stream->mark[i] != -1) {
					if (stream->mark[i] == 42) {
						n += snprintf(tmp, sizeof(tmp), "用油量: %d ml\n", stream->oil * 10);
					} else if (stream->mark[i] == 43) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "水温: %d 度\n", stream->water_temp);
					} else if (stream->mark[i] == 44) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "发动机进气温度: %d\n", stream->air_temp);
					} else if (stream->mark[i] == 46) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "电池当前电压: %.1f V\n", stream->voltage * 0.1);
					} else if (stream->mark[i] == 51) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "车速: %d Km/h\n", stream->car_speed);
					} else if (stream->mark[i] == 52) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "转速: %d rpm\n", stream->engine_speed);
					} else if (stream->mark[i] == 54) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "瞬时油耗: %.2f L/100Km\n", stream->instant_fuel_km * 0.01);
					} else if (stream->mark[i] == 55) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "瞬时油耗: %.2f L/h\n", stream->instant_fuel_h * 0.01);
					} else if (stream->mark[i] == 57) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "空气流量: %.2f g/s\n", stream->air_flow * 0.01);
					} else if (stream->mark[i] == 58) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "进气歧管绝对压力: %d\n", stream->press);
					} else if (stream->mark[i] == 64) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "滤波后剩余油量: %d %%\n", stream->remain_fuel);
					} else if (stream->mark[i] == 65) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "累计里程: %.1f Km\n", stream->mileage * 0.1);
					} else if (stream->mark[i] == 66) {
						n += snprintf(tmp+n, sizeof(tmp)-n, "里程ID: %d\n", stream->mileage_id);
					}
					i++;
				}
				n += snprintf(tmp+n, sizeof(tmp)-n, "体检时间: %s", dateftime(stream->ts, "%F %H:%M:%S").c_str());
				debug(LOG_DEBUG, "数据流: %s", tmp);
			}
		}
		break;
	case G2O_UPGRADE:
		{
			if (msg.upgrade == NULL)
				break;
			struct g2o_upgrade *upgrade = msg.upgrade;
			switch (upgrade->type) {
			case 0x01:
				debug(LOG_DEBUG, "请求最新版本: %s", upgrade->version);
				break;
			case 0x02:
				debug(LOG_DEBUG, "请求升级包数据: %s", upgrade->version);
				break;
			default:
				debug(LOG_DEBUG, "无有此类型升级: %d", upgrade->type);
				break;
			}
		}
		break;
	case G2O_BEAT_DATA:
		{
			debug(LOG_DEBUG, "心跳数据\n"
			"GSM 信号强度: %d", msg.gsm_sig_inensity);
		}
		break;
	case G2O_UNKNOWN_000A:
		debug(LOG_DEBUG, "非内部服务: %04X", msg.id);
		break;
	case G2O_UNKNOWN_000F:
		debug(LOG_DEBUG, "非内部服务: %04X", msg.id);
		break;
	default:
		debug(LOG_DEBUG, "未知类型: %04X", msg.id);
		break;
	}
}

void G2OSummary::writeDB(Connection *pConn)
{
	switch(msg.id) {
	case G2O_LOGIN:
		write_login(pConn);
		break;
	case G2O_CONFIG_INFO:
		write_config_info(pConn);
		break;
	case G2O_PACKED_DATA:
		{
			write_gps(pConn);
			write_data_stream(pConn);
		}
		break;
	case G2O_WARN_MSG:
		write_warn_msg(pConn);
		break;
	case G2O_TRAVEL_STCS:
		write_travel_stcs(pConn);
		break;
	case G2O_UNKNOWN_000A:
		break;
	case G2O_UNKNOWN_000F:
		break;
	case G2O_BEAT_DATA:
		write_beat_data(pConn);
		break;
	case G2O_UPGRADE:
		write_upgrade(pConn);
		break;
	default:
		break;
	}
}

void G2OSummary::createTB(Connection *pConn)
{
	try {
		switch(msg.id) {
		case G2O_LOGIN:
			create_login(pConn);
			break;
		case G2O_CONFIG_INFO:
			create_config_info(pConn);
			break;
		case G2O_PACKED_DATA:
			{
				create_gps(pConn);
				create_data_stream(pConn);
			}
			break;
		case G2O_WARN_MSG:
			create_warn_msg(pConn);
			break;
		case G2O_TRAVEL_STCS:
			create_travel_stcs(pConn);
			break;
		case G2O_UNKNOWN_000A:
			break;
		case G2O_UNKNOWN_000F:
			break;
		case G2O_BEAT_DATA:
			create_beat_data(pConn);
			break;
		case G2O_UPGRADE:
			create_upgrade(pConn);
			break;
		default:
			break;
		}
	} catch (mysqlpp::BadQuery &er) {
		debug(LOG_DEBUG, "Create table error: %s", er.what());
	}
}

void G2OSummary::write_login(Connection *pConn)
{
	Query query = pConn->query();
	struct g2o_login *login = msg.login;
	struct custime cur = timetocstm(msg.curtime);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	query << "INSERT INTO zb_g2o_login_" << szMonth << "(obdid,curtime,time,dp_code,dev_key,imei,dev_sim,version) VALUES(" << quote << m_obdid << ","
		<< msg.curtime << "," << msg.ts << "," << quote << login->dp_code << "," << quote << login->dev_key << "," << quote << login->dev_imei << ","
		<< quote << login->dev_sim << "," << quote << login->dev_version << ")";
	query.exec();
}

void G2OSummary::write_gps(Connection *pConn)
{
	struct g2o_gps *gps = msg.gps;
	struct custime cur;
	char format[100];
	Query query = pConn->query();
	while (gps) {
		cur = timetocstm(gps->ts);
		snprintf(szDay, sizeof(szDay), "%04d%02d%02d", cur.year, cur.month, cur.day);
		query << "INSERT INTO zb_g2o_gpsdata_" << szDay << "(obdid,curtime,time,mode,direct,speed,height,longitude,latitude) VALUES(" 
			<< quote << m_obdid << "," << msg.curtime << "," << gps->ts << "," << (int)gps->position_mode << "," << gps->direction << ","
			<< gps->speed << "," << gps->height;
		snprintf(format, sizeof(format), ",%.6lf,%.6lf", gps->longitude, gps->latitude);
		query << format << ")";
		query.exec();
		msg.gps = msg.gps->next;
		free(gps);
		gps = msg.gps;
	}
}

void G2OSummary::write_data_stream(Connection *pConn)
{
	struct g2o_data_stream *stream = msg.stream;
	struct custime cur;
	char format[1024];
	Query query = pConn->query();
	while (stream) {
		cur = timetocstm(stream->ts);
		snprintf(szDay, sizeof(szDay), "%04d%02d%02d", cur.year, cur.month, cur.day);
		query << "INSERT INTO zb_g2o_datastream_" << szDay << "(obdid,curtime,time,oil,water_temp,air_temp,voltage,car_speed,engine_speed,instant_fuel_km,instant_fuel_h,air_flow,press,remain_fuel,mileage,mileage_id) VALUES(" 
			<< quote << m_obdid << "," << msg.curtime << "," << stream->ts << "," << stream->oil * 10 << "," << stream->water_temp << "," << (int)stream->air_temp << ",";
		snprintf(format, sizeof(format), "%.1f,%d,%d,%.2f,%.2f,%.2f,%d,%d,%.1f,%d", stream->voltage * 0.1, stream->car_speed, stream->engine_speed, 
				stream->instant_fuel_km * 0.01, stream->instant_fuel_h * 0.01, stream->air_flow * 0.01, stream->press, stream->remain_fuel, 
				stream->mileage * 0.1, stream->mileage_id);
		query << format << ")";
		query.exec();
		msg.stream = stream->next;
		free(stream);
		stream = msg.stream;
	}
}

void G2OSummary::write_config_info(Connection *pConn)
{
}

void G2OSummary::write_warn_msg(Connection *pConn)
{
	struct g2o_warn *warn = msg.warn;
	if (!warn)
		return;
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.ts);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	query << "INSERT INTO zb_g2o_warnmsg_" << szMonth << "(obdid,curtime,time,type,descript) VALUES("
		<< quote << m_obdid << "," << msg.curtime << "," << msg.ts << "," << warn->id << ",";
	if (warn->warn_msg)
		query << quote << warn->warn_msg;
	else
		query << "''";
	query << ")";
	query.exec();
}

void G2OSummary::write_travel_stcs(Connection *pConn)
{
	Query query = pConn->query();
	struct g2o_travel *travel = msg.travel;
	if (!travel) {
		debug(LOG_DEBUG, "不能有这种事");
		return;
	}
	struct custime cur = timetocstm(travel->ts);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	switch (travel->type) {
	case G2O_TRAVEL_TYPE_START:
		query << "INSERT INTO zb_g2o_travel_" << szMonth << "(obdid,curtime,time,type,travel_no) VALUES("
			<< quote << m_obdid << "," << msg.ts << "," << travel->ts << "," 
			<< G2O_TRAVEL_TYPE_START << "," << travel->number << ")";
		query.exec();
		break;
	case G2O_TRAVEL_TYPE_FINISH:
		query << "INSERT INTO zb_g2o_travel_" << szMonth << "(obdid,curtime,time,type,travel_no,lng_start,lat_start,lng_end,lat_end,idling_cnt,idling_tm,mileage,oil) VALUES("
			<< quote << m_obdid << "," << msg.ts << "," << travel->ts << "," 
			<< G2O_TRAVEL_TYPE_FINISH << "," << travel->number << ","
			<< travel->lng_start << "," << travel->lat_start << "," << travel->lng_end << "," << travel->lat_end << "," 
			<< travel->idling_cnt << "," << travel->idling_tm << "," << travel->mileage << "," << travel->oil << ")";
		query.exec();
		break;
	}
}

void G2OSummary::write_beat_data(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.ts);
	struct custime max = cur;
	struct custime min = cur;
	max.hour = 23;
	max.min = 59;
	max.sec = 59;
	min.hour = 0;
	min.min = 0;
	min.sec = 0;
	snprintf(szYear,sizeof(szYear), "%04d", cur.year);
	query << "select time from zb_g2o_beat_" << szYear << " where obdid='" << m_obdid << "' and time >= " << custotime(min) << " and time <= " << custotime(max);
	StoreQueryResult res = query.store();
	if (res.num_rows() > 0)
		return;
	query << "INSERT INTO zb_g2o_beat_" << szYear << "(obdid,curtime,time,gsm_sig) VALUES(" << quote << m_obdid << "," 
		<< msg.curtime << "," << msg.ts << "," << (int)msg.gsm_sig_inensity << ")";
	query.exec();
}

void G2OSummary::write_upgrade(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur;
	struct g2o_upgrade *upgrade = msg.upgrade;
	if (upgrade->type == 0x01) {
		debug(LOG_DEBUG, "不存储");
		return;
	}
	if (strncmp(upgrade->version, "0001", 4) != 0)
		return;
	debug(LOG_DEBUG, "存下来");
	cur = timetocstm(msg.ts);
	snprintf(szYear, sizeof(szYear), "%04d", cur.year);
	query << "INSERT INTO zb_g2o_upgrade_" << szYear << "(obdid,curtime,time,version) VALUES("
		<< quote << m_obdid << "," << msg.curtime << "," << msg.ts << "," << get_g2o_version() << ")";
	query.exec();
}

void G2OSummary::create_login(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.curtime);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	query << "CREATE TABLE IF NOT EXISTS zb_g2o_login_" << szMonth <<
		"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) COMMENT '设备OBD序列号', " <<
		"curtime int unsigned NOT NULL COMMENT '登录请求的时间', time int unsigned NOT NULL COMMENT '登录请求附带的时间', " <<
		"dp_code char(3) NOT NULL COMMENT '开发者代码', dev_key char(33) NOT NULL COMMENT '设备密钥', " <<
		"imei char(16) NOT NULL COMMENT '设备IMEI码', dev_sim char(21) NOT NULL COMMENT 'SIM卡号', version char(8) NOT NULL COMMENT '设备软件版本号', " <<
		"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	query.exec();
}

void G2OSummary::create_gps(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur;
	struct g2o_gps *gps = msg.gps;
	for (; gps; gps = gps->next)
	{
		cur = timetocstm(gps->ts);
		snprintf(szDay, sizeof(szDay), "%04d%02d%02d", cur.year, cur.month, cur.day);
		query << "CREATE TABLE IF NOT EXISTS zb_g2o_gpsdata_" << szDay << 
			"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) COMMENT '设备OBD序列号', " <<
			"curtime int unsigned NOT NULL COMMENT '收到GPS的时间', time int unsigned NOT NULL COMMENT 'GPS产生的时间', " <<
			"mode int unsigned NOT NULL COMMENT '定位模式', direct int unsigned NOT NULL COMMENT '方向', " <<
			"speed int unsigned NOT NULL COMMENT '速度', height int unsigned NOT NULL COMMENT '高度', " <<
			"longitude float(10,6) unsigned COMMENT '经度', latitude float(10,6) unsigned COMMENT '纬度', " <<
			"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
		query.exec();
	}
}

void G2OSummary::create_data_stream(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur;
	struct g2o_data_stream *stream = msg.stream;
	for(; stream; stream = stream->next) {
		cur = timetocstm(stream->ts);
		snprintf(szDay, sizeof(szDay), "%04d%02d%02d", cur.year, cur.month, cur.day);
		query << "CREATE TABLE IF NOT EXISTS zb_g2o_datastream_" << szDay <<
			"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) NOT NULL COMMENT '设备OBD序列号', " <<
			"curtime int unsigned NOT NULL COMMENT '收到消息的时间', time int unsigned NOT NULL COMMENT '数据流自带时间', " << 
			"oil int unsigned NOT NULL COMMENT '用油量', water_temp int unsigned NOT NULL COMMENT '水温', air_temp int unsigned NOT NULL COMMENT '发动机进气温度', " <<
			"voltage float(4,1) unsigned NOT NULL COMMENT '电池当前电压', car_speed int unsigned NOT NULL COMMENT '车速', " <<
			"engine_speed int unsigned NOT NULL COMMENT '发动机转速', instant_fuel_km float(10,2) unsigned NOT NULL COMMENT '瞬时油耗，单位：L/100Km', " <<
			"instant_fuel_h float(10,2) unsigned NOT NULL COMMENT '瞬时油耗，单位：L/h', air_flow float(10,2) unsigned NOT NULL COMMENT '空气流量：单位: g/s', " <<
			"press int unsigned NOT NULL COMMENT '进气歧管绝对压力: kPa', remain_fuel int unsigned NOT NULL COMMENT '滤波后剩余油量: %', " <<
			"mileage float(10,1) unsigned NOT NULL COMMENT '累计里程', mileage_id int unsigned NOT NULL COMMENT '里程ID', " <<
			"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
		query.exec();
	}
}

void G2OSummary::create_config_info(Connection *pConn)
{
}

void G2OSummary::create_warn_msg(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.ts);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	query << "CREATE TABLE IF NOT EXISTS zb_g2o_warnmsg_" << szMonth << 
		"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) NOT NULL COMMENT '设备OBD序列号', " <<
		"curtime int unsigned NOT NULL COMMENT '收到消息的时间', time int unsigned NOT NULL COMMENT '报警时间', " <<
		"type int unsigned NOT NULL COMMENT '报警类型', descript varchar(50) NOT NULL DEFAULT '' COMMENT '报警的相关参数', " <<
		"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	query.exec();
}

void G2OSummary::create_travel_stcs(Connection *pConn)
{
	Query query = pConn->query();
	struct g2o_travel *travel = msg.travel;
	struct custime cur = timetocstm(travel->ts);
	snprintf(szMonth, sizeof(szMonth), "%04d%02d", cur.year, cur.month);
	query << "CREATE TABLE IF NOT EXISTS zb_g2o_travel_" << szMonth << 
		"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) NOT NULL COMMENT '设备OBD序列号', " <<
		"curtime int unsigned NOT NULL COMMENT '行程信息数据包时间', time int unsigned NOT NULL COMMENT '行程开始或结束时间', " <<
		"type int unsigned NOT NULL COMMENT '行程开始: 0; 行程结束: 1', travel_no int unsigned NOT NULL COMMENT '行程序号', " <<
		"lng_start float(10,6) unsigned NOT NULL DEFAULT '0' COMMENT '起始经度', lat_start float(10,6) unsigned NOT NULL DEFAULT '0' COMMENT '起始纬度', " <<
		"lng_end float(10,6) unsigned NOT NULL DEFAULT '0' COMMENT '结束经度', lat_end float(10,6) unsigned NOT NULL DEFAULT '0' COMMENT '结束纬度', " <<
		"idling_cnt int unsigned NOT NULL DEFAULT '0' COMMENT '怠速次数', idling_tm int unsigned NOT NULL DEFAULT '0' COMMENT '怠速时间', " <<
		"mileage float(10,2) unsigned NOT NULL DEFAULT '0' COMMENT '里程', " <<
		"oil float(10,2) unsigned NOT NULL DEFAULT '0' COMMENT '油耗: 升', " <<
		"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	query.exec();
}

void G2OSummary::create_beat_data(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.ts);
	snprintf(szYear, sizeof(szYear), "%04d", cur.year);
	query << "CREATE TABLE IF NOT EXISTS zb_g2o_beat_" << szYear << 
		"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) NOT NULL COMMENT '设备OBD序列号', " <<
		"curtime int unsigned NOT NULL COMMENT '当前时间', time int unsigned NOT NULL COMMENT '心跳数据时间', " <<
		"gsm_sig int unsigned NOT NULL COMMENT 'GSM信号强度', " <<
		"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	query.exec();
}

void G2OSummary::create_upgrade(Connection *pConn)
{
	Query query = pConn->query();
	struct custime cur = timetocstm(msg.ts);
	snprintf(szYear, sizeof(szYear), "%04d", cur.year);
	query << "CREATE TABLE IF NOT EXISTS zb_g2o_upgrade_" << szYear << 
		"(id int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', obdid char(14) NOT NULL COMMENT '设备OBD序列号', " <<
		"curtime int unsigned NOT NULL COMMENT '当前时间', time int unsigned NOT NULL COMMENT '附带时间', " <<
		"version int unsigned NOT NULL COMMENT '软件版本号', " <<
		"primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	query.exec();
}

